﻿using System;
using System.Collections.Generic;
using System.Linq;
using Altairis.FluffyCloud.Data;
using WikiPlex;
using WikiPlex.Compilation;
using WikiPlex.Compilation.Macros;
using WikiPlex.Formatting.Renderers;

namespace Altairis.FluffyCloud.WebCore.Controls {

    public class WikiMarkup : Altairis.Sewen.WebControls.WikiMarkup {

        protected override IEnumerable<IMacro> RegisterMacros() {
            return base.RegisterMacros().Union(new[] {
                new InternalLinkMacro()
            });
        }

        protected override IEnumerable<IRenderer> RegisterRenderers() {
            return base.RegisterRenderers().Union(new[] {
                new InternalLinkRenderer()
            });
        }

        #region InternalLinks

        internal class InternalLinkMacro : IMacro {
            public const string SCOPE_NAME = "InternalLink";

            public string Id {
                get {
                    return "Altairis.Nemesis.Events.InternalLinkMacro";
                }
            }

            public virtual IList<MacroRule> Rules {
                get {
                    return new List<MacroRule> {
                        new MacroRule(EscapeRegexPatterns.CurlyBraceEscape),
                        new MacroRule(@"(?i)(\[)((?>[a-z]+:[^\]]+))(\])",
                            new Dictionary<int, string> {
                                { 1, ScopeName.Remove },
                                { 2, SCOPE_NAME },
                                { 3, ScopeName.Remove }
                            }
                        )
                    };
                }
            }
        }

        internal class InternalLinkRenderer : Renderer {
            private static string ERROR_FORMAT = "<strike>{0}</strike>";
            private static string LINK_FORMAT = "<a href=\"{0}\" title=\"{2}\">{1}</a>";

            protected override ICollection<string> ScopeNames {
                get {
                    return new[] { InternalLinkMacro.SCOPE_NAME };
                }
            }

            protected override string PerformExpand(string scopeName, string input, Func<string, string> htmlEncode, Func<string, string> attributeEncode) {
                var prefix = input.Substring(0, input.IndexOf(':')).ToLower();
                input = input.Substring(input.IndexOf(':') + 1);

                string text, href, title;
                switch (prefix) {
                    case "user":
                    case "profile":
                        var inputData = input.Split(new[] { '|' }, 2);
                        var userName = inputData.Length == 1 ? input : inputData[1];

                        using (var dc = new FluffyDbContext()) {
                            var usr = dc.Users.SingleOrDefault(x => x.UserName.Equals(userName, StringComparison.CurrentCultureIgnoreCase));
                            if (usr == null) return string.Format(ERROR_FORMAT, "Uživatel '" + userName + "' neexistuje.");
                            if (inputData.Length == 1) {
                                text = htmlEncode(usr.UserName.ToUpper());
                                title = usr.Comment;
                            }
                            else {
                                text = htmlEncode(inputData[0]);
                                title = string.Format("{0}: {1}", usr.UserName, usr.Comment);
                            }
                            href = string.Format("/users/{0}", userName);
                        }
                        break;

                    case "forum":
                    case "topic":
                        int topicId;
                        if (!int.TryParse(input, out topicId)) return string.Format(ERROR_FORMAT, "'" + input + "' není platné ID fóra.");
                        using (var dc = new FluffyDbContext()) {
                            var topic = dc.Topics.FirstOrDefault(x => x.TopicId == topicId);
                            if (topic == null) return string.Format(ERROR_FORMAT, "Fórum " + input + " neexistuje.");
                            text = htmlEncode(topic.Name);
                            href = string.Format("/forum/{0}", topic.TopicId);
                            title = topic.Description;
                        }
                        break;
                    default:
                        return string.Format(ERROR_FORMAT, "Neznámý prefix '" + prefix + "'");
                }

                // Return formatted link
                return string.Format(LINK_FORMAT, attributeEncode(href), text, attributeEncode(title));
            }
        }

        #endregion InternalLinks
    }
}